As computer science has evolved, object oriented programming has become one of many familiar models designers and programmers utilize to implement functionality within computer systems. The object model generally is defined by a class structure that includes class members providing both methods and associated data elements belonging to the class. The class members thus provide/define desired functionality within a computer program, wherein an object is declared as an instance of a particular class. As is commonplace, objects often must exchange data and/or invoke other objects operating on the same platform and/or communicate with objects belonging to remote platforms. In order to communicate between objects, interface systems and standards have been developed to define how objects may communicate and/or interact with one another.
A familiar system for communicating and interfacing between objects is known as the Component Object Model (COM), wherein another similar system is referred to as the Common Object Request Brokers Architecture (CORBA). Still yet other communication interfaces may be defined in languages such as the JAVA programming language within an operating framework of a Java Virtual Machine, for example. As these and other systems have been developed however, two common object architectures or models generally have emerged and may generally be defined in terms of managed and unmanaged object systems, for example.
Managed objects may be allocated from a heap within a managed software environment and are generally not responsible for managing associated object lifetimes. Managed objects may be described in terms of a data type (e.g., metadata) and automatically collected (e.g., reclaimed) by a managed environment “garbage collector” that removes the object from memory when the object is no longer being accessed. In contrast, unmanaged objects may be allocated from a standard operating system heap, wherein the object itself is responsible for freeing memory it employs when references to the object no longer exist. This may be accomplished through well-known techniques such as reference counting, for example.
As described above, managed objects may be allocated from a managed heap and automatically garbage collected. In order to achieve this, references to managed objects are traced. When a last reference to an object is removed, the garbage collector reclaims the memory occupied by the object mitigating the need to reference count managed objects. Thus, a managed environment essentially handles reference counting internally. Tracing is possible within managed code because the managed environment keeps track of outstanding references that exist on an object. As each new object reference is declared within managed code, the managed environment adds the reference to a list of live references.
At any given time, the managed environment, rather than the object itself, is thus aware of live references that exist on a given object. As references fall out of scope or change value, the list of live references is updated, and as long as a reference remains within managed code, the managed environment is able to trace it. Along with the object lifetime issues described above, managed and unmanaged object systems generally differ in many other significant ways. These differences may include how the object systems provide object interfaces within the respective object systems, how data is structured and/or defined, and how errors and exceptions are handled, for example.
Relating to object execution environments, dynamic programming languages offer a variety of different code types from which to develop a plurality of applications. Dynamically typed languages such as Perl, Scheme, Ruby, Python, Smalltalk, and so forth, traditionally utilize various tagging schemes to overcome the overhead of allocating small (usually word-sized) objects on the heap, but still keeping the benefits of a uniform representation of values for parametric operations. For instance, assuming that pointers are aligned at 4-byte boundaries, a common technique is to use the least-significant bit of a 32-bit value to distinguish between a pointer and an immediate value. On Windows-based system, for example, one might consider setting two most significant bits to 1 since pointers are not supposed to point in the topmost memory segments.
It is apparent to many system architects however, that programs that employ such encodings (e.g., encodings to distinguish between pointers and integer values) are not verifiable when executed on a managed execution environment such as a Common Language Runtime or a Java Virtual Machine. Currently, one verifiable manner to achieve a uniform representation is to utilize boxing (e.g., boxing associates an integer with an object), however, operating on boxed values can be an order of a magnitude slower with respect to processor execution performance than working on the underlying value directly.